package cmd

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"

	"BookStack/internal/infrastructure/core"
)

// Migration 迁移记录
type Migration struct {
	ID         uint      `gorm:"primarykey"`
	Version    string    `gorm:"size:100;not null;uniqueIndex"`
	Name       string    `gorm:"size:255;not null"`
	ExecutedAt time.Time `gorm:"not null"`
}

// TableName 表名
func (Migration) TableName() string {
	return "migrations"
}

// MigrateDB 执行数据库迁移
func MigrateDB() error {
	config := core.GetConfig()

	// 连接数据库
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
		config.DB.Username,
		config.DB.Password,
		config.DB.Host,
		config.DB.Port,
		config.DB.Name,
		config.DB.Charset)

	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		return fmt.Errorf("连接数据库失败: %v", err)
	}

	// 确保迁移表存在
	if err := ensureMigrationTable(db); err != nil {
		return fmt.Errorf("创建迁移表失败: %v", err)
	}

	// 读取迁移文件
	migrationsDir := "scripts/migration"
	files, err := os.ReadDir(migrationsDir)
	if err != nil {
		return fmt.Errorf("读取迁移目录失败: %v", err)
	}

	// 获取已执行的迁移
	var executedMigrations []Migration
	if err := db.Find(&executedMigrations).Error; err != nil {
		return fmt.Errorf("查询已执行迁移失败: %v", err)
	}

	// 构建已执行迁移版本集合以便快速查找
	executedVersions := make(map[string]bool)
	for _, m := range executedMigrations {
		executedVersions[m.Version] = true
	}

	// 收集所有迁移文件并排序
	var migrationFiles []string
	for _, file := range files {
		if !file.IsDir() && strings.HasSuffix(file.Name(), ".up.sql") {
			migrationFiles = append(migrationFiles, file.Name())
		}
	}
	sort.Strings(migrationFiles)

	// 执行未应用的迁移
	for _, fileName := range migrationFiles {
		// 提取版本和名称
		version := strings.Split(fileName, "_")[0]
		name := strings.TrimSuffix(fileName, ".up.sql")

		// 检查是否已执行
		if executedVersions[version] {
			fmt.Printf("跳过已执行的迁移: %s\n", name)
			continue
		}

		// 读取并执行迁移
		content, err := os.ReadFile(filepath.Join(migrationsDir, fileName))
		if err != nil {
			return fmt.Errorf("读取迁移文件失败: %v", err)
		}

		// 开始事务
		tx := db.Begin()

		// 执行迁移
		if err := tx.Exec(string(content)).Error; err != nil {
			tx.Rollback()
			return fmt.Errorf("执行迁移失败 %s: %v", fileName, err)
		}

		// 记录迁移版本
		migration := Migration{
			Version:    version,
			Name:       name,
			ExecutedAt: time.Now(),
		}
		if err := tx.Create(&migration).Error; err != nil {
			tx.Rollback()
			return fmt.Errorf("记录迁移版本失败: %v", err)
		}

		// 提交事务
		if err := tx.Commit().Error; err != nil {
			return fmt.Errorf("提交迁移事务失败: %v", err)
		}

		fmt.Printf("已执行迁移: %s\n", fileName)
	}

	return nil
}

// ensureMigrationTable 确保迁移表存在
func ensureMigrationTable(db *gorm.DB) error {
	// 检查迁移表是否存在
	if db.Migrator().HasTable(&Migration{}) {
		return nil
	}

	// 创建迁移表
	return db.AutoMigrate(&Migration{})
}

// InstallDB 安装初始数据库
// Install 安装初始数据
func Install() error {
	return InstallDB()
}
